<template>
  <el-select
    v-model="Model"
    v-bind="$attrs"
    v-on="$listeners"
    style="width: -webkit-fill-available"
    multiple
    collapse-tags
    @remove-tag="removeTag"
    :placeholder="placeholder"
  >
    <template #empty>
      <div style="width: 750px; margin: 10px">
        <EvForm
          v-bind="$attrs"
          ref="dataSourceForm"
          :itemStyle="{ marginRight: '2%', marginBottom: '10px', width: '95%' }"
          :autoWidth="false"
          @autoEmit="autoEmit"
        >
        </EvForm>
        <EvTable
          :options="tableOptions"
          :tablePage="page"
          :showCountDetail="false"
          @changeEvent="handleModelChange"
          @clearEvent="clearEvent"
          @handlePageChange="handlePageChange"
          ref="EvTable"
        >
        </EvTable>
      </div>
    </template>
  </el-select>
</template>

<script>
export default {
  props: {
    value: {
      type: [String, Number, Array],
    },
    columns: {
      type: Array,
      default: () => [],
    },
    fieldValue: String,
    fieldLabel: String,
    fieldLock: {
      type: Array,
      default: () => [],
    },
    microservices: {
      type: String,
      default: "",
    },
    resource: {
      type: String,
      default: "",
    },
    placeholder: {
      type: String,
      default: "",
    },
  },
  data() {
    return {
      selectedModel: this.value,
      Model: "",
      page: {
        currentPage: 1,
        pageSize: 5,
        total: 0,
      },
      searchQueries: {},
      data: [],
      pageDataCache: {}, // 新增的对象用于存储每页的数据
    };
  },
  async mounted() {
    await this.loadData();

    if (this.selectedModel) {
      this.Model = this.selectedModel.map((valueItem) =>
        this.getValueFromObject(
          this.data?.filter(
            (item) =>
              this.getValueFromObject(item, this.fieldValue) === this.getValueFromObject(valueItem, this.fieldValue)
          )[0],
          this.fieldLabel
        )
      );

      this.emitVmodel();
    }
  },
  beforeDestroy() {
    this.clearData();
  },
  watch: {
    value(newVal) {
      this.selectedModel = newVal;
    },
    searchQueries() {
      this.page.currentPage = 1;
    },
  },
  computed: {
    tableOptions() {
      return {
        data: this.computedOptions,
        columns: this.columns,
        height: "320px",
        toolbarConfig: {
          custom: false,
          slots: {
            buttons: "toolbar_buttons",
          },
        },
        checkboxConfig: {
          checkMethod: this.checkMethod,
          trigger: "row",
        },
      };
    },
    computedOptions() {
      let filteredOptions = JSON.parse(JSON.stringify(this.data));
      const dataSourceForm = this.$attrs.dataSourceFormOptions.dataSourceForm;
      this.$attrs.dataSourceFormOptions.dataSourceFormItems.forEach((item) => {
        const { model } = item;
        const value = this.getValueFromObject(dataSourceForm, model);
        if (value.trim() !== "") {
          const searchValue = value.trim().toLowerCase();
          filteredOptions = filteredOptions.filter((option) => {
            return String(this.getValueFromObject(option, model)).toLowerCase().includes(searchValue);
          });
        }
      });

      // 根据分页信息对 options 进行分页
      const start = (this.page.currentPage - 1) * this.page.pageSize;
      const end = start + this.page.pageSize;
      this.updateTotal(filteredOptions.length);
      this.$nextTick(() => {
        this.setCheckbox();
      });
      return filteredOptions.slice(start, end);
    },
  },
  methods: {
    emitOptions() {
      this.$emit("optionSet", this.data);
    },
    emitSelectData(value) {
      this.$emit("selectData", value);
    },
    emitVmodel() {
      this.$emit("input", this.selectedModel);
      this.$emit("change", this.selectedModel);
    },
    getPageNumber(valueItem) {
      const index = this.data.findIndex(
        (item) => this.getValueFromObject(item, this.fieldValue) === this.getValueFromObject(valueItem, this.fieldValue)
      );
      if (index !== -1) {
        return Math.ceil((index + 1) / this.page.pageSize);
      }
      return null;
    },
    checkMethod({ row }) {
      for (let i = 0; i < this.fieldLock.length; i++) {
        if (!this.getValueFromObject(row, this.fieldLock[i])) {
          return false;
        }
      }
      return true;
    },
    clearData() {
      this.data = [];
    },
    removeTag(tag) {
      const tagObj = this.data.find((item) => this.getValueFromObject(item, this.fieldLabel) === tag);
      const tagValue = this.getValueFromObject(tagObj, this.fieldValue);
      const index = this.selectedModel.findIndex((item) => {
        return item === tagValue;
      });

      if (index !== -1) {
        this.selectedModel.splice(index, 1);
      }
      this.$refs.EvTable.setCheckboxRow(tagObj, false);
    },
    setCheckbox() {
      if (!this.selectedModel.length) {
        return;
      }
      const checkboxes = this.selectedModel.map((valueItem) => {
        if (typeof valueItem === "object") {
          const page = this.getPageNumber(valueItem);
          if (!page) {
            return;
          }
          if (!this.pageDataCache[page]) {
            this.pageDataCache[page] = [];
          }

          if (
            !this.pageDataCache[page].some(
              (item) =>
                this.getValueFromObject(item, this.fieldValue) === this.getValueFromObject(valueItem, this.fieldValue)
            )
          ) {
            this.pageDataCache[page].push(valueItem);
          }

          return this.data.find(
            (item) =>
              this.getValueFromObject(item, this.fieldValue) === this.getValueFromObject(valueItem, this.fieldValue)
          );
        } else {
          return this.data.find((item) => this.getValueFromObject(item, this.fieldValue) === valueItem);
        }
      });
      this.$refs.EvTable.setCheckboxRow(checkboxes, true);
      this.$refs.EvTable.selectRecords = checkboxes;
      this.emitSelectData(checkboxes);
    },
    getValueFromObject(obj, path) {
      const keys = path.split(".");
      let value = obj;
      for (const key of keys) {
        if (value && typeof value === "object") {
          value = value[key];
        } else {
          value = undefined;
          break;
        }
      }
      return value;
    },
    updateTotal(value) {
      this.page.total = value;
    },
    loadData() {
      return new Promise((resolve) => {
        this.$server()
          .query(this.microservices, this.resource, null, null, null, true)
          .then((response) => {
            this.page.total = response.total;
            this.data = response.list;
            this.emitOptions();
            this.setCheckbox();
            resolve();
          })
          .catch((response) => {
            this.$message.error(response.data.message);
          });
      });
    },
    /**
     * 自动触发对搜索查询对象中指定模型的值进行更新或删除。
     * 如果提供的值经过trim处理后为空字符串，则从搜索查询对象中删除该模型；
     * 否则，将该模型和值设置到搜索查询对象中。
     *
     * @param {string} model - 模型名称，对应搜索查询中的键。
     * @param {string} value - 与模型关联的值。
     */
    autoEmit(model, value) {
      // 对值进行trim处理后，如果为空则删除对应模型；非空则更新模型的值
      if (value.trim() === "") {
        this.$delete(this.searchQueries, model);
      } else {
        this.$set(this.searchQueries, model, value);
      }
    },
    handlePageChange({ currentPage, pageSize }) {
      this.page.currentPage = currentPage;
      this.page.pageSize = pageSize;
      this.setCheckbox();
    },
    clearEvent() {
      this.selectedModel = [];
      this.pageDataCache = {};
      this.Model = "";
      this.emitVmodel();
      return;
    },
    handleModelChange(data) {
      this.pageDataCache[this.page.currentPage] = data;
      const selectObjCache = Object.values(this.pageDataCache).flat();
      const fieldLabelValues = selectObjCache.map((item) => this.getValueFromObject(item, this.fieldLabel));
      const fieldValueValues = selectObjCache.map((item) => this.getValueFromObject(item, this.fieldValue));
      this.Model = fieldLabelValues;
      this.selectedModel = [...fieldValueValues];
      this.emitVmodel();
      this.setCheckbox();
    },
  },
};
</script>
